#ifdef __aarch64__
    .text
    .align 5
    .global MatmulFloatNeon32OptRemain
#ifndef __APPLE__
    .type MatmulFloatNeon32OptRemain, %function
#endif

// void MatmulFloatNeon32Remain(const float *a, const float *b, float *c, int depth
//                        int row, int col, size_t stride)
// r0: a
// r1: b
// r2: c
// r3: depth
// r4: row
// r5: col
// r6: stride
// only for winograd
MatmulFloatNeon32OptRemain:
    // r4-r8 and q4-q7 must be saved according to https://static.docs.arm.com/ihi0042/i/aapcs32.pdf
    push {r0-r3}
    push {r4-r8, r10, r11, lr}
    vpush {q4-q7}
    add sp, sp, #96

    mov lr, #16 // sizeof(float) * 4
    mul r12, r3, lr // block stride of lhs/rhs: sizeof(float) * 8 * depth
    mov lr, #4
    mul r11, r5, r6
    mul r10, r6, lr
    mul r11, r11, lr
    mul r10, r10, lr

    ldr r4, [sp, #12]
    ldr r5, [sp, #16]
    ldr r6, [sp, #20]
    cmp r4, #4
    ble LoopH4

    LoopH8:
        ldr r4, [sp, #12] // reload lhs row
        ldr r0, [sp] // reload lhs ptr
        ldr r2, [sp, #8] // reload dst ptr

        LoopW8:
            ldr r1, [sp, #4] // reload rhs ptr
            ldr r3, [sp, #12] // reload depth
            veor q8, q8, q8
            veor q9, q9, q9
            veor q10, q10, q10
            veor q11, q11, q11
            veor q12, q12, q12
            veor q13, q13, q13
            veor q14, q14, q14
            veor q15, q15, q15

            LoopD8:
                vld1.32 {q0, q1}, [r0]!
                vld1.32 {q3}, [r1]!
                vmla.f32 q8, q3, d0[0]
                vmla.f32 q9, q3, d0[1]
                vld1.32 {q2}, [r0]!
                vmla.f32 q10, q3, d1[0]
                vmla.f32 q11, q3, d1[1]
                vmla.f32 q12, q3, d2[0]
                vmla.f32 q13, q3, d2[1]
                vmla.f32 q14, q3, d3[0]
                vmla.f32 q15, q3, d3[1]

                subs r3, r3, #1
                bgt LoopD8

                vst1.32 {q8}, [r2], r11
                vst1.32 {q9}, [r2], r11
                vst1.32 {q10}, [r2], r11
                vst1.32 {q11}, [r2], r11
                vst1.32 {q12}, [r2], r11
                vst1.32 {q13}, [r2], r11
                vst1.32 {q14}, [r2], r11
                vst1.32 {q15}, [r2], r11

            subs r4, r4, #8 // lhs row - 8
            bgt LoopW8

        subs x5, x5, #4 // rhs col - 4
        ldr r1, [sp, #4]
        add r1, r1, r12 // rhs ptr + stride
        str r1, [sp, #4]
        ldr r2, [sp, #8]
        add r2, r2, r10
        str r2, [sp, #8]
        bgt LoopH8

        b End

    LoopH4:
        ldr r4, [sp, #12] // reload lhs row
        ldr r0, [sp] // reload lhs ptr
        ldr r2, [sp, #8] // reload dst ptr

        LoopW4:
            ldr r1, [sp, #4] // reload rhs ptr
            ldr r3, [sp, #12] // reload depth
            veor q12, q12, q12
            veor q13, q13, q13
            veor q14, q14, q14
            veor q15, q15, q15

            LoopD4:
                vld1.32 {q0}, [r0]!
                vld1.32 {q3}, [r1]!
                vmla.f32 q12, q3, d0[0]
                vmla.f32 q13, q3, d0[1]
                vld1.32 {q1, q2}, [r0]!
                vmla.f32 q14, q3, d1[0]
                vmla.f32 q15, q3, d1[1]

                subs r3, r3, #1
                bgt LoopD8

                vst1.32 {q12}, [r2], r11
                vst1.32 {q13}, [r2], r11
                vst1.32 {q14}, [r2], r11
                vst1.32 {q15}, [r2], r11

            subs r4, r4, #4 // lhs row - 4
            bgt LoopW4

        subs x5, x5, #4 // rhs col - 4
        ldr r1, [sp, #4]
        add r1, r1, r12 // rhs ptr + stride
        str r1, [sp, #4]
        ldr r2, [sp, #8]
        add r2, r2, r10
        str r2, [sp, #8]
        bgt LoopH4

End:
    sub sp, sp, #96
    vpop {q4-q7}
    pop {r4-r8, r10, r11, pc}
    pop {r0-r3}
#endif
